#ifndef LIBPLEIADES_PLEIADES_H
#define LIBPLEIADES_PLEIADES_H

#include "com_nhncorp_pleiades_client_NativeLockEventHandler.h"
#include "list.h"

#include <sys/types.h>
#include <sys/stat.h>

#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>

#include <jni.h>

#ifndef O_RDONLY
#define O_RDONLY 1
#endif

#ifndef O_WRONLY 
#define O_WRONLY 2
#endif

#ifndef EINTERNAL
#define EINTERNAL 255 
#endif


/** All APIs set errno to meaningful values */
#ifdef __cplusplus
extern  "C" {
#endif

#ifndef __cplusplus
#ifdef bool 
#undef bool 
#endif
typedef unsigned char bool;
#define false 0 
#define true (!false)
#endif 

typedef enum {
    PLEIADES_LOCK_SHARED = 0,
    PLEIADES_LOCK_EXCLUSIVE = 1
} pleiades_lock_mode_t;   

enum pleiades_event_mask_e {
	PLEIADES_CONTENTS_CHANGED = 1,
	PLEIADES_NODE_ADDED = 2,
	PLEIADES_NODE_REMOVED = 4,
	PLEIADES_NODE_MODIFIED = 8, 
	PLEIADES_MASTER_FAILOVER = 16,
	PLEIADES_SESSION_WARNING = 32,
	PLEIADES_SESSION_SAFE = 64,
	PLEIADES_SESSION_EXPIRED = 128,
	PLEIADES_LOCK_EXPIRED = 256,
	PLEIADES_CLIENT_EXPIRED = 512
};

typedef enum pleiades_event_mask_e pleiades_event_mask_t;
typedef enum pleiades_event_mask_e pleiades_event_t;

typedef enum {
	PLEIADES_EQ, /* equality operator */
	PLEIADES_LT, /* less than operator */
	PLEIADES_GT, /* greater operator */
	PLEIADES_GE, /* greater or equal operator */
	PLEIADES_LE, /* less or equal operator */
	PLEIADES_PF, /* has prefix operator */
	PLEIADES_SF, /* has suffix operator */
	PLEIADES_ANY,/* any opeator, this is default */
	PLEIADES_NE, /* not equal operator */
	PLEIADES_SS  /* substring operator */
} pleiades_operator_t;

typedef struct {
	struct list_head link;
	pleiades_operator_t op;
	char *key;
} pleiades_condition_t;

typedef struct {
	struct list_head link;
	struct list_head cond_list;
} pleiades_constraint_t;

typedef struct {
	struct list_head constr_list;
} pleiades_lock_event_filter_t;

/** 
 * pleiades_lock_status_t - Information about lock
 */
typedef struct  {
    char *creator;
    char *lock_id;        
    int64_t generation_number;
    int32_t lock_mode;
} pleiades_lock_status_t;

/** 
 * pleiades_lock_meta_data_t - Information about a file node.
 */
typedef struct  {
    char *creator;
    char *lock_id;        
    int64_t generation_number;
    int32_t lock_mode;
    char* content_key;
} pleiades_lock_meta_data_t;    

/** 
 * pleiades_lock_event_data_t - Information about an event.
 */
typedef struct  {
    char *creator;
    char *lock_id;        
    int64_t generation_number;
    int32_t type;
    bool is_dir;
} pleiades_lock_event_data_t;     

/** 
 * pleiades_lock_event_monitor_t 
 */
typedef struct  {
	struct list_head link;
	void (*notify_event)(pleiades_event_t, pleiades_lock_event_data_t *);
	pleiades_lock_event_filter_t *filter;
} pleiades_lock_event_monitor_t;

/**
 * pleiades client structure 
 */
typedef struct {
    void *obj;
	int event_mask;
} pleiades_client_t;

/** 
 * event handler structure
 */
typedef struct {
    struct list_head link;
    void *obj;
    void (*contents_modified)(pleiades_lock_event_data_t *);
    void (*node_added)(pleiades_lock_event_data_t *);
    void (*node_removed)(pleiades_lock_event_data_t *);
    void (*node_modified)(pleiades_lock_event_data_t *);
    void (*master_failover)();
    void (*session_warning)();
    void (*session_safe)();
    void (*session_expired)();
    void (*client_expired)(pleiades_lock_event_data_t *);
    void (*lock_expired)(pleiades_lock_event_data_t *);
	struct list_head event_monitors;
} pleiades_event_handler_t;     

/** Returns the client proxy of pleiades */    
pleiades_client_t *pleiades_create_client(const char* service, 
											const char* owner_id);

/** Terminates session. Releases allocated resources. */
int pleiades_close_client(pleiades_client_t *client);

/** Returns the client event handler of pleiades */
pleiades_event_handler_t *pleiades_create_event_handler();

/** Releases pleiades event handler allocated memory */
void pleiades_close_event_handler(pleiades_event_handler_t *handler);

/** Attempt to acquire a lock. Do not block if the lock cannot be obtained immediately */    
int pleiades_get_lock(pleiades_client_t *client, const char* path, 
						pleiades_lock_mode_t mode);

/** Check whether acquire a lock. Do not block */
int pleiades_try_lock(pleiades_client_t *client, const char* path, 
						pleiades_lock_mode_t mode);
						
/** Check whether memory lock exists */
int pleiades_lock_exist(pleiades_client_t *client, const char* path);

/** Returns lock status data for the children of a path */
pleiades_lock_status_t *pleiades_list_lock( pleiades_client_t *client, 
						const char* path, int *num_entries);						

/** Releases the currently held lock */
int pleiades_release_lock(pleiades_client_t *client, const char* path, 
						pleiades_lock_mode_t mode);

/** Returns the contents of the node (files only) */
int pleiades_get_contents(pleiades_client_t *client, const char* path, 
						char* contents, int contents_buf_size);

/** Sets the contents of the node (files only) */
int pleiades_set_contents(pleiades_client_t *client, const char* path, 
						const char* contents);    

/** Check whether node exists on the file system */
int pleiades_node_exist(pleiades_client_t *client, const char* path);

/** Returns the meta data for the node */
pleiades_lock_meta_data_t *pleiades_get_meta_data(pleiades_client_t *client, 
						const char* path);

/** Returns the names and meta data for the children of a directory */
pleiades_lock_meta_data_t *pleiades_get_children_meta_data(
						pleiades_client_t *client, const char* path, 
						int *num_entries, bool include_dir);		

/** Create file based persistent lock with event notification */
int pleiades_create_file_node(pleiades_client_t *client, const char* path, 
						const char* key, bool overwrite);

/** Create directory based persistent lock with event notification */
int pleiades_create_dir_node(pleiades_client_t *client, const char* path, 
						const char* key);

/** Deletes the node with recursive option */
int pleiades_delete_node(pleiades_client_t *client, const char* path, 
						bool recursive);

/** Terminates session. Does not deallocate resources */
int pleiades_poison(pleiades_client_t *client);

/** Restart session. Does not allocate resources */
int pleiades_restart_session(pleiades_client_t *client);

/** set/unset various events handler callback function */
void pleiades_set_contents_modified(pleiades_event_handler_t *handler, 
						void (*func)(pleiades_lock_event_data_t *));
void pleiades_set_node_added(pleiades_event_handler_t *handler, 
						void (*func)(pleiades_lock_event_data_t *));
void pleiades_set_node_removed(pleiades_event_handler_t *handler, 
						void (*func)(pleiades_lock_event_data_t *));
void pleiades_set_node_modified(pleiades_event_handler_t *handler, 
						void (*func)(pleiades_lock_event_data_t *));
void pleiades_set_master_failover(pleiades_event_handler_t *handler, 
						void (*func)());
void pleiades_set_session_warning(pleiades_event_handler_t *handler, 
						void (*func)());
void pleiades_set_session_safe(pleiades_event_handler_t *handler, 
						void (*func)());
void pleiades_set_session_expired(pleiades_event_handler_t *handler, 
						void (*func)());
void pleiades_set_client_expired(pleiades_event_handler_t *handler, 
						void (*func)(pleiades_lock_event_data_t *));
void pleiades_set_lock_expired(pleiades_event_handler_t *handler, 
						void (*func)(pleiades_lock_event_data_t *));
void pleiades_unset_contents_modified(pleiades_event_handler_t *handler); 
void pleiades_unset_node_added(pleiades_event_handler_t *handler); 
void pleiades_unset_node_removed(pleiades_event_handler_t *handler); 
void pleiades_unset_node_modified(pleiades_event_handler_t *handler); 
void pleiades_unset_master_failover(pleiades_event_handler_t *handler); 
void pleiades_unset_session_warning(pleiades_event_handler_t *handler); 
void pleiades_unset_session_safe(pleiades_event_handler_t *handler); 
void pleiades_unset_session_expired(pleiades_event_handler_t *handler); 
void pleiades_unset_client_expired(pleiades_event_handler_t *handler); 
void pleiades_unset_lock_expired(pleiades_event_handler_t *handler); 
void pleiades_unset_all_events(pleiades_event_handler_t *handler);

/** event filtering api **/
pleiades_constraint_t *pleiades_create_constraint();
void pleiades_destroy_constraint(pleiades_constraint_t *constr);
void pleiades_add_condition(pleiades_constraint_t *constr, 
						pleiades_operator_t op, const char *key);
pleiades_lock_event_filter_t *pleiades_create_lock_event_filter();
void pleiades_destroy_lock_event_filter(pleiades_lock_event_filter_t *filter);
void pleiades_add_constraint(pleiades_lock_event_filter_t *filter, 
						pleiades_constraint_t *constr);
void pleiades_remove_constraint(pleiades_lock_event_filter_t *filter, 
						pleiades_operator_t op);
void pleiades_add_lock_event_monitor(pleiades_event_handler_t *handler, 
		void (*event_monitor)(pleiades_event_t, pleiades_lock_event_data_t *),
		pleiades_lock_event_filter_t *filter);
void pleiades_remove_event_monitor(pleiades_event_handler_t *handler, 
	  	void (*event_monitor)(pleiades_event_t, pleiades_lock_event_data_t *));

/** Setup and start default event handler based on FIFO queue */
int pleiades_set_event_handler(pleiades_client_t *client, 
					pleiades_event_handler_t *handler, int event_mask);

/** Get the first event of the queue and does not remove*/
pleiades_lock_event_data_t *pleiades_read_event(
						pleiades_event_handler_t *handler);

/** Get the first event of the queue and remove the event*/
pleiades_lock_event_data_t *pleiades_take_event(
						pleiades_event_handler_t *handler);

/** Get multiple events from queue and remove them*/
pleiades_lock_event_data_t *pleiades_take_multi_event(
						pleiades_event_handler_t *handler, int *num_entries, 
						int max_count);		

/** Releases allocated pleiades_lock_meta_data_t resources. */
void pleiades_free_lock_meta_data(pleiades_lock_meta_data_t *meta_data, 
						int num_entries);

/** Releases allocated pleiades_lock_event_data_t resources. */
void pleiades_free_lock_event_data(pleiades_lock_event_data_t *event_data, 
						int num_entries);	
#ifdef __cplusplus
}
#endif

#endif /*LIBPLEIADES_PLEIADES_H*/
